package com.example.service.impl;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.common.base.service.impl.BaseServiceImpl;
import com.example.common.enums.ResponseCodeEnum;
import com.example.common.utils.ApiResult;
import com.example.common.utils.CacheUtils;
import com.example.common.utils.HttpUtils;
import com.example.config.webscoket.WebSocket;
import com.example.dao.*;
import com.example.model.entity.*;
import com.example.model.query.*;
import com.example.model.vo.CalledVo;
import com.example.model.vo.SocketVo;
import com.example.service.TEquipmentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

/**
 *  Service接口实现类
 *
 * @author Tellsea
 * @Description Created on 2020-12-11
 */
@Service
@Slf4j
public class TEquipmentServiceImpl extends BaseServiceImpl<TEquipmentMapper, TEquipment> implements TEquipmentService {

    @Autowired
    private TEquipmentMapper equipmentMapper;

    @Autowired
    private TAreaMapper areaMapper;

    @Autowired
    private TEquipmentPartMapper equipmentPartMapper;

    @Autowired
    private TPlanMapper planMapper;

    @Autowired
    private TUserMapper userMapper;

    @Autowired
    private TWarningMapper warningMapper;

    @Autowired
    private TPlanRecordMapper planRecordMapper;

    @Resource
    private WebSocket webSocket;

    @Autowired
    private TPartPlanMapper partPlanMapper;

    @Autowired
    private TPlanRecordDetailMapper planRecordDetailMapper;

    @Value("${idispatch_addr:}")
    private String idispatch_addr;

    @Override
    public ApiResult<TEquipmentQuery> pageUserVoByQuery(TEquipmentQuery query) {
        query.setOptimizeCountSql(false);
        Long current = query.getCurrent();
        query.setCurrent(1L);
        if(StringUtils.isNotBlank(query.getEquipmentNum()) || StringUtils.isNotBlank(query.getEquipmentName())){
            query.setAreaId(null);
        }
        Integer total = equipmentMapper.countByQuery(query);
        query.setTotal(total);
        query.setCurrent(current);
        equipmentMapper.pageInfoByQuery(query);
        List list = query.getRecords();
        for (int i = 0; i < list.size(); i++) {
            TEquipmentQuery obj = (TEquipmentQuery)list.get(i);
            if(StringUtils.isNotBlank(obj.getAreaId())){
                TArea area = areaMapper.selectById(obj.getAreaId());
                if(area != null){
                    obj.setAreaName(area.getAreaName());
                }
            }
        }
        return new ApiResult<>(query);
    }
    @Override
    public  ApiResult<List<TEquipment>> getList(){
        QueryWrapper<TEquipment> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TEquipment::getIsValid,1L);
        List<TEquipment> sysOrganizationList = equipmentMapper.selectList(queryWrapper);
        return new ApiResult<>(sysOrganizationList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> saveT(TEquipmentQuery equipmentQuery){
        QueryWrapper<TEquipment> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TEquipment::getIsValid,1L).eq(TEquipment::getEquipmentNum,equipmentQuery.getEquipmentNum());
        int count = equipmentMapper.selectCount(queryWrapper);
        if(count > 0){
            return new ApiResult<>(ResponseCodeEnum.MALL_SERVICE_ISREG_CUSTOMER_FALSE);
        }
        TEquipment equipment = new TEquipment();
        BeanUtils.copyProperties(equipmentQuery,equipment);
        equipment.setCreateDate(LocalDateTime.now());
        equipmentMapper.insert(equipment);
        for (int i = 0; i < equipmentQuery.getPartNum(); i++) {
            TEquipmentPart part = new TEquipmentPart();
            part.setPartNum(Long.valueOf(i+1));
            part.setPartName("通道"+Long.valueOf(i+1));
            part.setIsAuto(1L);
            part.setEquipmentId(equipment.getEquipmentId());
            part.setCreateDate(LocalDateTime.now());
            equipmentPartMapper.insert(part);
        }
        return new ApiResult<>(Boolean.TRUE);
    }

    @Override
    public ApiResult<TEquipmentQuery> getInfo(String id) {
        TEquipment equipment = equipmentMapper.selectById(id);
        TEquipmentQuery query = new TEquipmentQuery();
        if(equipment != null){
            BeanUtils.copyProperties(equipment,query);
            TArea area = areaMapper.selectById(query.getAreaId());
            if(area != null){
                query.setAreaName(area.getAreaName());
            }
            QueryWrapper<TEquipmentPart> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(TEquipmentPart::getIsValid,1L).eq(TEquipmentPart::getEquipmentId,id);
            List<TEquipmentPart> partList = equipmentPartMapper.selectList(queryWrapper);
            if(partList.size()>0){
                List<TEquipmentPartQuery> partQueryList = new ArrayList<>();
                for (int i = 0; i < partList.size(); i++) {
                    TEquipmentPart part = partList.get(i);
                    TEquipmentPartQuery partQuery = new TEquipmentPartQuery();
                    BeanUtils.copyProperties(part,partQuery);
                    QueryWrapper<TPartPlan> planQueryWrapper = new QueryWrapper<>();
                    planQueryWrapper.lambda().eq(TPartPlan::getIsValid,1L)
                            .eq(TPartPlan::getPartId,part.getPartId());
                    partQuery.setPartPlanList(partPlanMapper.selectList(planQueryWrapper));
                    partQueryList.add(partQuery);
                }
                query.setEquipmentPartList(partQueryList);
            }
        }
        return new ApiResult<>(query);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> modify(TEquipmentQuery query ){
        TEquipment equipment = new TEquipment();
        BeanUtils.copyProperties(query,equipment);
        equipment.setUpdateDate(LocalDateTime.now());
        equipmentMapper.updateById(equipment);
        //删除通道
        QueryWrapper<TEquipmentPart> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TEquipmentPart::getEquipmentId,query.getEquipmentId()).eq(TEquipmentPart::getIsValid,1L);
        TEquipmentPart updatePart = new TEquipmentPart();
        updatePart.setIsValid(0L);
        equipmentPartMapper.update(updatePart,queryWrapper);
        if(query.getEquipmentPartList().size()>0){
            List<TEquipmentPartQuery> partList = query.getEquipmentPartList();
            for(TEquipmentPartQuery partQuery : partList){
                TEquipmentPart part = new TEquipmentPart();
                BeanUtils.copyProperties(partQuery,part);
               int updateNum =  equipmentPartMapper.updateById(part);
               if(updateNum == 0){
                   part.setEquipmentId(query.getEquipmentId());
                   part.setCreateDate(LocalDateTime.now());
                   equipmentPartMapper.insert(part);
               }
               //删除预案
               partPlanMapper.delectPlanByPartId(part.getPartId());
               if(partQuery.getPartPlanList() != null){
                   for(TPartPlan partPlan: partQuery.getPartPlanList()){
                       if(StringUtils.isBlank(partPlan.getPlanId())){
                           break;
                       }
                       partPlan.setPartPlanId(null);
                       partPlan.setPartId(part.getPartId());
                       partPlan.setPlanId(partPlan.getPlanId());
                       partPlan.setCreateDate(LocalDateTime.now());
                       partPlanMapper.insert(partPlan);
                   }
               }
            }
        }
        return new ApiResult<>(Boolean.TRUE);
    }

    @Override
    public synchronized void handleWarningInfo(String mac_id,int num,String message,Long status) throws Exception{
        QueryWrapper<TEquipment> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TEquipment::getIsValid,1L).eq(TEquipment::getEquipmentNum,mac_id);
        List<TEquipment> equipmentList = equipmentMapper.selectList(queryWrapper);
        if(equipmentList.size() == 0){
            log.info("编号:"+mac_id+",设备不存在");
            return ;
        }
        TEquipment equipment = equipmentList.get(0);
        QueryWrapper<TEquipmentPart> partQueryWrapper = new QueryWrapper<>();
        partQueryWrapper.lambda().eq(TEquipmentPart::getIsValid,1L)
                .eq(TEquipmentPart::getPartNum,num)
                .eq(TEquipmentPart::getEquipmentId,equipment.getEquipmentId());
        List<TEquipmentPart> partList = equipmentPartMapper.selectList(partQueryWrapper);
        if(partList.size() ==0 ){
            log.info("编号:"+mac_id+",通道："+num+",通道配置不存在");
            return ;
        }
        dealMessage(message,status,partList.get(0));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized ApiResult<Boolean>  dealMessage(String message,Long status,TEquipmentPart part) throws Exception {
        //当前通道状态
        Long isDoNow = status;
        //查询缓存中该通道告警状态
        Object statusObj = CacheUtils.get("partId"+part.getPartId());
        //上一次通道状态
        Long isDo = 1L;
        if(statusObj == null){
            isDo = part.getIsDo();
            CacheUtils.put("partId"+part.getPartId(),isDo);
        }else {
            isDo =Long.valueOf(String.valueOf(statusObj));
        }
        //状态相同不做处理，退出
        if(isDo == isDoNow){
            return new ApiResult<>(Boolean.TRUE);
        }
        //缓存中修改该通道告警状态
        CacheUtils.put("partId"+part.getPartId(),isDoNow);
        //告警
        if(isDoNow == 0L){
            log.info("===================================================================" +
                    "=============================生成推送告警=============================" +
                    "====================================================================");
            //生成告警记录
            TWarning warning = new TWarning();
            warning.setEquipmentId(part.getEquipmentId());
            warning.setPartId(part.getPartId());
            warning.setCreateDate(LocalDateTime.now());
            warning.setWarningInfo(message);
            warning.setSourceId(part.getSourceId());
//            warning.setIsDoPlan(part.getIsAuto() == 1L? 1L:0L);
            warningMapper.insert(warning);
            //webSocket推送
            sendWebSocketMess(part,0L);
            //判断是否主动触发预案
            if(part.getIsAuto() == 1L){
                ApiResult<Boolean> apiResult = startPlan(part,warning.getWarningId());
            }
        }else{
           //更新告警结束时间
            QueryWrapper<TWarning> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(TWarning::getIsValid,1L)
                                    .eq(TWarning::getPartId,part.getPartId())
                                    .orderByDesc(TWarning::getCreateDate)
                                    .isNull(TWarning::getUpdateDate);
            List<TWarning> warningList = warningMapper.selectList(queryWrapper);
            if(warningList.size() > 0){
                TWarning warning = warningList.get(0);
                warning.setUpdateDate(LocalDateTime.now());
                warningMapper.updateById(warning);
            }
            //推送到websocket
            log.info("===================================================================" +
                    "=============================更新结束告警=============================" +
                    "====================================================================");
            sendWebSocketMess(part,1L);
        }
        return new ApiResult<>(Boolean.TRUE);
    }

    @Override
    public ApiResult<Boolean> idispatchLogin(TUser user) throws Exception {
        //强制登出
        Map paramMap = new HashMap<>();
        paramMap.put("username",user.getUserName());
        JSONObject resultJson = HttpUtils.post(idispatch_addr+"/forcelogout",paramMap);
        int status = (int)resultJson.get("status");
        if(status != 200){
            return new ApiResult<>(-100,"强制退出失败");
        }
        log.info("强制退出成功");
        Thread.sleep(1000);
        paramMap.clear();
        Map map = new HashMap<>();
        map.put("@id","10000");
        map.put("@type","UserLogin");
        map.put("userName",user.getUserName());
        map.put("userPwd",user.getPassword());
        paramMap.put("request",map);
        resultJson = HttpUtils.post(idispatch_addr+"/login",paramMap);
        String msg = (String)resultJson.get("msg");
        if(!msg.equals("success")) {
            return new ApiResult<>(-101,"登录失败");
        }
        String tokensign =(String) resultJson.get("tokensign");
        String operatorid =(String) resultJson.get("operatorid");
        CacheUtils.put("myToken", tokensign);
        CacheUtils.put("myOperatorId", operatorid);
        log.info("myToken:"+tokensign);
        log.info("登录成功");
        return new ApiResult<>(Boolean.TRUE);
    }

    @Override
    public ApiResult<Boolean> startPlan(TEquipmentPart part,String warningId) throws Exception {
        TWarning warning = new TWarning();
        warning.setWarningId(warningId);
        //查出所有预案
        QueryWrapper<TPartPlan> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TPartPlan::getIsValid,1L).eq(TPartPlan::getPartId,part.getPartId());
        List<TPartPlan> partplanList = partPlanMapper.selectList(queryWrapper);
        List<TPlan> planList = new ArrayList<>();
        for(TPartPlan partPlan: partplanList){
            TPlan plan = planMapper.selectById(partPlan.getPlanId());
            if(plan != null){
                planList.add(plan);
            }
        }
        Object token = CacheUtils.get("myToken");
        if(token == null){
            QueryWrapper<TUser> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.lambda().eq(TUser::getIsValid,1L);
            TUser user = userMapper.selectOne(userQueryWrapper);
            ApiResult<Boolean> apiResult = idispatchLogin(user);
            if(apiResult.getCode() != 0){
//                return new ApiResult<>(-101,);
                warning.setRemarks("启动预案失败，reson:登录失败");
                warningMapper.updateById(warning);
                log.info("---------------------------调度系统登录失败--------------------");
                return new ApiResult<>(-789,"启动预案失败，reson:登录失败");
//                throw new Exception("登录失败");
            }
        }
        for(TPlan plan : planList){
            if(plan.getPlanType() == 1L){//短信
                this.sendSms(plan,warningId);
            }else if(plan.getPlanType() == 2L){//广播
                this.broadcast(plan,warningId);
            }else if(plan.getPlanType() == 3L){//摄像头
                this.openVideo(plan,warningId,part);
            }
        }
        //预案触发成功，更新标识
        warning.setIsDoPlan(1L);
        warning.setRemarks("");
        warningMapper.updateById(warning);
        return new ApiResult<>(Boolean.TRUE);
    }
    /*
    * 发送短信(统一单发)
    */
    public ApiResult<Boolean> sendSms(TPlan plan,String warningId) throws Exception {
        plan.getCallTel();
        String[] telArr = plan.getCallTel().split(",");
        //生成触发记录
        TPlanRecord record = createPlanRecoed(plan, warningId);
        for (int i = 0; i < telArr.length; i++) {
            String tel = telArr[i];
            if(StringUtils.isBlank(tel)){
                break;
            }
            Map paramMap = new HashMap<>();
            Map map = new HashMap<>();
            map.put("@id", record.getPlanRecordId());
            map.put("@type","SmsSend");
            map.put("smsContent",plan.getSmsContent());
            map.put("smsContacts",tel);
            map.put("smsFormat","sms");
            map.put("smsType","single");
            paramMap.put("request",map);
            JSONObject resultJson = HttpUtils.postAddHeader(idispatch_addr+"/smsflow",paramMap);
            String msg =(String) resultJson.get("msg");
            if(!msg.equals("try")){
                //return new ApiResult<>(-102,"短信请求发起失败");
//            throw new Exception("短信请求发起失败");
                log.info("短信请求发起失败");
            }
        }
        log.info("短信请求发起成功");
        return new ApiResult<>(Boolean.TRUE);
    }

    /*
     * 打开广播
     * */
    public ApiResult<Boolean> broadcast(TPlan plan,String warningId) throws Exception {
        //获取手柄
        JSONObject operatorJson = this.operatorQuery();
        String callingDevice = (String)operatorJson.get("mainTel");
        Map paramMap = new HashMap<>();
        List<CalledVo> list = new ArrayList<>();
        String[] telArr = plan.getCallTel().split(",");
        for (int i = 0; i < telArr.length; i++) {
            CalledVo vo = new CalledVo();
            vo.setCalledDevice(telArr[i]);
            vo.setUserID("");
            list.add(vo);
        }
        Map map = new HashMap<>();
        //生成触发记录
        TPlanRecord record = createPlanRecoed(plan,warningId);
        map.put("@id", record.getPlanRecordId());
        map.put("@type","BroadcastCall");
        map.put("callingDevice",callingDevice);//主叫号码
        map.put("called",list);
        map.put("time",plan.getBroadcastNum());
        map.put("callMode","file");
        map.put("fileName",plan.getBroadcastFile());
        map.put("callLoop",plan.getBroadcastNum());
        map.put("alarmLevel",plan.getBroadcastLevel());
        paramMap.put("request",map);
        JSONObject resultJson = HttpUtils.postAddHeader(idispatch_addr+"/makecall",paramMap);
        String msg =(String) resultJson.get("msg");
        if(!msg.equals("try")){
//            return new ApiResult<>(-103,"广播请求发起失败");
            throw new Exception("广播请求发起失败");
        }
        log.info("广播请求发起成功");
        return new ApiResult<>(Boolean.TRUE);
    }

    /*
     * 打开摄像头
     * */
    ApiResult<Boolean> openVideo(TPlan plan,String warningId,TEquipmentPart part){
        //生成触发记录
        TPlanRecord record = createPlanRecoed(plan,warningId);
        TPlanRecordQuery query = new TPlanRecordQuery();
        BeanUtils.copyProperties(record,query);
        //记录详情，记录打开摄像头
        String[] videoArr = plan.getVideoId().split(",");
        for (int i = 0; i < videoArr.length; i++) {
            saveRecordDetail(record.getPlanRecordId(),1L,videoArr[i]);
        }
        //推送到webSocket
//        if(webSocket.webSocketSet.size() >0){
//            query.setEquipmentPart(part);
//            TEquipment equipment = equipmentMapper.selectById(part.getEquipmentId());
//            if(equipment != null){
//                query.setEquipment(equipment);
//            }
//            SocketVo vo  = new SocketVo();
//            vo.setType("openVideo");
//            vo.setSource("warning");
//            vo.setData(JSONUtil.parseObj(query));
//            webSocket.GroupSending(JSONUtil.toJsonStr(vo));
//        }
        return new ApiResult<>(Boolean.TRUE);
    }

    /*
    * 	操作员信息查询--主手柄
    * 不需要传参数，只需要头里带token
    * */
    JSONObject operatorQuery() throws Exception {
        Map paramMap = new HashMap<>();
        JSONObject resultJson = HttpUtils.postAddHeader(idispatch_addr+"/operatorquery",paramMap);
        String msg =(String) resultJson.get("msg");
        if(!msg.equals("success")){
            String reason = (String) resultJson.get("reason");
            throw new Exception("操作员信息查询失败,reason:"+reason);
        }
        JSONObject json =(JSONObject) resultJson.get("eventdata");
        return json;
    }


    /*
     * 生成预案记录
     * */
    TPlanRecord createPlanRecoed(TPlan plan,String warningId){
        TPlanRecord planRecord = new TPlanRecord();
        BeanUtils.copyProperties(plan,planRecord);
        planRecord.setPlanRecordId(null);
        planRecord.setCreateDate(LocalDateTime.now());
        planRecord.setStatus(0L);
        planRecord.setWarningId(warningId);
        planRecordMapper.insert(planRecord);
        return planRecord;
    }
    /*
     * 生成预案记录详情（）本方法摄像头使用
     * */
    void saveRecordDetail(String mesgId,Long calledResult ,String calledDevice){
        TPlanRecordDetail detail = new TPlanRecordDetail();
        detail.setPlanRecordId(mesgId);
        detail.setCreateDate(LocalDateTime.now());
        detail.setDetailObj(calledDevice);
        detail.setStatus(calledResult);
        planRecordDetailMapper.insert(detail);
    }
    /*
     * 推送告警上报信息
     * @param isOver 0告警开始/1告警结束
     */
    void sendWebSocketMess(TEquipmentPart part,Long isOver){
        //推送到websocket
        if(webSocket.webSocketSet.size() >0){
            TEquipmentPartQuery query = new TEquipmentPartQuery();
            BeanUtils.copyProperties(part,query);
            TEquipment equipment = equipmentMapper.selectById(part.getEquipmentId());
            query.setEquipmentName(equipment.getEquipmentName());
            query.setIsOver(isOver);
            SocketVo vo  = new SocketVo();
            vo.setSource("warning");
            vo.setType("warning");
            vo.setData(JSONUtil.parseObj(query));
            webSocket.GroupSending(JSONUtil.toJsonStr(vo),"warning");
        }
    }
}

